/*
 * RMTransactionManagementModule.java    ver   27/nov/2009
 *
 * Copyright (c) 2009 mentalsmash.org
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * The use of the Apache License does not indicate that this project is
 * affiliated with the Apache Software Foundation.
 */
package org.mentalsmash.tazio.transactions.management.rm;

import org.mentalsmash.tazio.net.ril.RemoteInvoker;
import org.mentalsmash.tazio.net.ril.exceptions.NoSuchRemoteObjectException;
import org.mentalsmash.tazio.transactions.TransactionalSystemRuntimeException;
import org.mentalsmash.tazio.transactions.UserTransactionManager;
import org.mentalsmash.tazio.transactions.management.SystemTransactionManager;
import org.mentalsmash.tazio.transactions.management.TransactionManagementModule;
import org.mentalsmash.tazio.transactions.management.TransactionManagerMonitor;
import org.mentalsmash.tazio.transactions.management.TxStateObserver;
import org.mentalsmash.tazio.transactions.management.ValidationAgent;
import org.mentalsmash.tazio.transactions.modules.OutcomeObserver;
import org.mentalsmash.tazio.transactions.modules.TxQueue;

import com.google.inject.Provides;
import com.google.inject.Scopes;
import com.google.inject.name.Named;
import com.google.inject.name.Names;

/**
 * @version ver 27/nov/2009
 * @author Andrea Reale <andrea.reale@gmail.com>
 * 
 */
public class RMTransactionManagementModule extends TransactionManagementModule {

    /**
     * @param name
     */
    public RMTransactionManagementModule(String name) {
	super(name);
    }




    private final static int TX_QUEUE_SIZE = 20;

    /**
     * Timeout for a thread who ascked for a commit, and waits to be notified for its outcome
     */
    private final static int WAIT_TIMEOUT = 20000000;

    
    
    
    @Override
    protected void configure() {

	super.configure();
	
	

	bind(RMTransactionManager.class).to(RMTransactionManagerImpl.class);
	// TODO: fix the next two bindings that is there just because of a poor
	// design of the TazioRootSet
	bind(SystemTransactionManager.class).to(
		RMMockUserTransactionManager.class);
	bind(UserTransactionManager.class).to(
		RMMockUserTransactionManager.class);

	// bind(RMTransactionsFacade.class).toProvider(RMTransactionsFacadeProvider.class).in(Scopes.SINGLETON);

	bind(GroupTransactionsFacade.class).toProvider(GroupTransactionsFacadeRILProvider.class).asEagerSingleton();


	bind(RMTransactionsFacadeImpl.class).toProvider(RMTransactionsFacadeProvider.class).in(Scopes.SINGLETON);
	bind(TxStateObserver.class).annotatedWith(OutcomeObserver.class).to(RMTransactionsFacadeImpl.class);
	bind(RMTransactionsFacade.class).to(RMTransactionsFacadeImpl.class);
	
	bind(ValidationAgent.class).to(RMBackwardValidationAgent.class);
	
	// capacity of the transactions queue
	bindConstant().annotatedWith(TxQueue.class).to(TX_QUEUE_SIZE);
	bindConstant().annotatedWith(Names.named("RMFacadeWaitTimeout")).to(
		WAIT_TIMEOUT);

	// JMX Binding
	// bind(MBeanServer.class).toInstance(
	// ManagementFactory.getPlatformMBeanServer());
	bind(TransactionManagerMonitor.class).to(
		RMTransactionManagementMonitor.class);
	bind(RMFacadeMonitorMBean.class).to(RMFacadeMonitor.class)
		.asEagerSingleton();

    }
    
    @Provides
    @Named("GroupProxy")
    final GroupTransactionsFacade getGroupProxy(final RemoteInvoker invoker) {
	try {
	    return invoker.getRemoteObject(GroupTransactionsFacade.RIL_IDENTIFIER, GroupTransactionsFacade.class);
	} catch (NoSuchRemoteObjectException e) {
	    throw new TransactionalSystemRuntimeException(e);
	}
	
    }
    

    //private Object facadeCreationLock = new Object();
   // private RMTransactionsFacadeImpl facadeImpl = null;

//    @Provides
//    @Singleton
//    @Inject
//    RMTransactionsFacade getRMTransactionsFacade(final RemoteInvoker invoker,
//	    RMTransactionManager tm,
//	    @Named("GroupProxy") GroupTransactionsFacade groupFacade,
//	    RootSet rs, @Named("RMFacadeWaitTimeout") int waitTimeout) {
//	this.buildRMTransactionsFacadeImpl(invoker, tm, groupFacade, rs,
//		waitTimeout);
//	return this.facadeImpl;
//    }
    
    
    
//    @Provides
//    @Singleton
//    RMTransactionsFacadeImpl getRMTransactionsFacadeImpl(final RemoteInvoker invoker,
//	    RMTransactionManager tm,
//	    @Named("GroupProxy") GroupTransactionsFacade groupFacade,
//	    RootSet rs, @Named("RMFacadeWaitTimeout") int waitTimeout) {
//	
//	RMTransactionsFacadeImpl instance = new RMTransactionsFacadeImpl(tm, groupFacade, rs,
//		waitTimeout);
//	System.out.println("stocazzo!");
//
//	try {
//	    invoker.getRegistry().registerObject(
//		    RMTransactionsFacade.RIL_IDENTIFIER, instance);
//	} catch (OIDAlreadyInUseException e) {
//	    throw new TransactionalSystemRuntimeException(e);
//	}
//	
//	return instance;
//
//    }
    
//    @Provides
//    @Singleton
//    @Inject
//    @OutcomeObserver
//    TxStateObserver getTxStateObserver(final RemoteInvoker invoker,
//	    RMTransactionManager tm,
//	    @Named("GroupProxy") GroupTransactionsFacade groupFacade,
//	    RootSet rs, @Named("RMFacadeWaitTimeout") int waitTimeout) {
//	this.buildRMTransactionsFacadeImpl(invoker, tm, groupFacade, rs,
//		waitTimeout);
//	return this.facadeImpl;
//    }
//
//    private void buildRMTransactionsFacadeImpl(RemoteInvoker invoker,
//	    RMTransactionManager tm, GroupTransactionsFacade groupFacade,
//	    RootSet rs, int waitTimeout) {
//	synchronized (facadeCreationLock) {
//	    if (this.facadeImpl == null) {
////		System.err.println("building...");
//		this.facadeImpl = new RMTransactionsFacadeImpl(tm, groupFacade,
//			rs, waitTimeout);
//
//		try {
//		    invoker.getRegistry().registerObject(
//			    RMTransactionsFacade.RIL_IDENTIFIER, facadeImpl);
//		} catch (OIDAlreadyInUseException e) {
//		    throw new TransactionalSystemRuntimeException(e);
//		}
//	    }
//	}
//
//    }

}
